package com.inetools.gwt.gajaxs.client;

import java.util.LinkedHashSet;

public abstract class CallbackeeAbstractImpl implements Callbackee {
	public interface PostSendingRequestListener {
		public void dispatchNotice();
	}
	
	protected LinkedHashSet<PostSendingRequestListener> postSendingRequestListenerLinkedHashSet = 
		new LinkedHashSet<PostSendingRequestListener>();
	
	public boolean addPostSendingRequestListener( PostSendingRequestListener listener) {
		if ( listener == null) return false;
		return postSendingRequestListenerLinkedHashSet.add( listener);
	}
	public boolean removePostSendingRequestListener( PostSendingRequestListener listener) {
		if ( listener == null) return false;
		return postSendingRequestListenerLinkedHashSet.remove( listener);
	}
	public void clearPostSendingRequestListeners() {
		postSendingRequestListenerLinkedHashSet = new LinkedHashSet<PostSendingRequestListener>();
	}
	
	public void dispatchRequestSentNotice() {
		for( PostSendingRequestListener listener : postSendingRequestListenerLinkedHashSet) {
			listener.dispatchNotice();
		} // for
	}
	
	protected native void sendRequest( Callbackee handlerInstance) /*-{
		// Construct id of call back insidence into callbackBaseName variable ---------------------
		var callbackBaseName = 
			handlerInstance.@com.inetools.gwt.gajaxs.client.Callbackee::getCallbackBaseName()();
		var callbackTimeStamp = 
			handlerInstance.@com.inetools.gwt.gajaxs.client.Callbackee::getCallbackTimeStamp()();
		if ( callbackTimeStamp == null) {
			callbackTimeStamp = new Date().getTime().toString();
			handlerInstance.@com.inetools.gwt.gajaxs.client.Callbackee::setCallbackTimeStamp(Ljava/lang/String;)( callbackTimeStamp);
		}
		callbackBaseName = 
			callbackBaseName + callbackTimeStamp + "_" + handlerInstance.@com.inetools.gwt.gajaxs.client.Callbackee::getCallbackId()();
		
		var callbackCountName = callbackBaseName + "Count"; 
		// ----------------------------------------------------------------------------------------
		
		var count = 0;
		if ( typeof ( window[ callbackCountName]) == "number") {
			// Clean up previous attempt residue --------------------------------------------------
			count = window[ callbackCountName];
			
			var lastCallbackName = callbackBaseName + "_" + count;
			var lastCallbackCompletionFlagName = lastCallbackName + "_CompleteOn";
			
			// Remove script DOM element and callback elements.
			var failedScriptNode = document.getElementById( lastCallbackName);
			if ( failedScriptNode) {
				document.body.removeChild( failedScriptNode);
			}
			delete window[ lastCallbackName];
			
			if ( window[ lastCallbackCompletionFlagName]) { // Callback method has been executed
				delete window[ lastCallbackCompletionFlagName];
				delete window[ callbackCountName];
				return;
			}
			else { // Callback method has not been called yet
				
				delete window[ lastCallbackCompletionFlagName];
				
				// Give up when attempt exceeds maxCount ------------------------------------------
				var maxCount = 
					handlerInstance.@com.inetools.gwt.gajaxs.client.Callbackee::getCallbackMaxCount()();
				if ( count >= maxCount) {
					delete window[ callbackCountName];
					// Notify failure to listeners
					handlerInstance.@com.inetools.gwt.gajaxs.client.Callbackee::fireCallbackFailureEvent()();
					return;
				}
				// --------------------------------------------------------------------------------			
			}
			// ------------------------------------------------------------------------------------
		}
	
		window[ callbackCountName] = ++count;
		
		var callbackName = callbackBaseName + "_" + count;
		var callbackCompletionFlagName = callbackName + "_CompleteOn";
		
		// Define the callback function on the window object.
		// It receives the JSON data returned by the server as an argument.
		window[ callbackName] = 
			function( jsonObj) {
				// Hand over jsonObj to handler
				handlerInstance.@com.inetools.gwt.gajaxs.client.Callbackee::fireCallbackEvent(Lcom/google/gwt/core/client/JavaScriptObject;)( jsonObj);
				// Flag to sign that the JSON callback was called.
				window[ callbackCompletionFlagName] = true;
			};
		
		// Create script DOM element to send request
		var script = document.createElement( "script");
		script.id = callbackName;
		script.setAttribute( "type", "text/javascript");
		// The src attribute points to the URL that will retrieve the JSON data wrapped in a callback function.
		var requestURL = 
			encodeURI( 
				handlerInstance.@com.inetools.gwt.gajaxs.client.Callbackee::getRequestUrlForCallback()() + callbackName);
		script.setAttribute( "src", requestURL);
		
		// Send request by attaching the script element to the document body.
		document.body.appendChild( script);

		// Notify to listeners that request has been sent 
		handlerInstance.@com.inetools.gwt.gajaxs.client.Callbackee::dispatchRequestSentNotice();

		// Set time out
		var callbackRequestTimeout = 
			handlerInstance.@com.inetools.gwt.gajaxs.client.Callbackee::getCallbackRequestTimeOut()();
		callbackRequestTimeout = callbackRequestTimeout * count;
		
		// Set timeout to JSON download.
		// A timeout function is defined to check for an unresponsive server or network problem;
		// it checks a flag to see if the JSON callback was ever called.
		var jsTimeoutObjReferrer = 
			setTimeout(
				function() {
					handlerInstance.@com.inetools.gwt.gajaxs.client.Callbackee::postCallbackRequestTimeout()();
				}, 
				callbackRequestTimeout
				);
		handlerInstance.@com.inetools.gwt.gajaxs.client.Callbackee::setJsTimeoutObjReferrerForCallback(I)( jsTimeoutObjReferrer); 
	}-*/;
	
	@Override
	public void postCallbackRequestTimeout() {
		sendRequest( this);
	}
}
